package com.example.hjt_java_web_homework3.dao;

import com.example.hjt_java_web_homework3.model.Device;
import com.example.hjt_java_web_homework3.util.DatabaseUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Repository;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Li Chun Hei
 * @date 31/10/2025
 * @description
 */

@Repository
public class DeviceDao {
    private static final Logger logger = LogManager.getLogger(DeviceDao.class);

    public List<Device> findAll() {
        List<Device> devices = new ArrayList<>();
        String sql = "SELECT * FROM devices ORDER BY create_time DESC";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {

            while (rs.next()) {
                devices.add(mapResultSetToDevice(rs));
            }
            logger.info("Found {} devices", devices.size());

        } catch (SQLException e) {
            logger.error("Failed to find all devices", e);
        }
        return devices;
    }

    public Device findById(Long id) {
        String sql = "SELECT * FROM devices WHERE id = ?";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            pstmt.setLong(1, id);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    logger.info("Found device with id: {}", id);
                    return mapResultSetToDevice(rs);
                }
            }

        } catch (SQLException e) {
            logger.error("Failed to find device by id: {}", id, e);
        }
        return null;
    }

    public Device findByDeviceId(String deviceId) {
        String sql = "SELECT * FROM devices WHERE device_id = ?";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            pstmt.setString(1, deviceId);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    return mapResultSetToDevice(rs);
                }
            }

        } catch (SQLException e) {
            logger.error("Failed to find device by deviceId: {}", deviceId, e);
        }
        return null;
    }

    public boolean save(Device device) {
        String sql = "INSERT INTO devices (name, type, location, device_id, status) VALUES (?, ?, ?, ?, ?)";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {

            pstmt.setString(1, device.getName());
            pstmt.setString(2, device.getType());
            pstmt.setString(3, device.getLocation());
            pstmt.setString(4, device.getDeviceId());
            pstmt.setBoolean(5, device.getStatus());

            int affectedRows = pstmt.executeUpdate();
            if (affectedRows > 0) {
                try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                    if (generatedKeys.next()) {
                        device.setId(generatedKeys.getLong(1));
                    }
                }
                logger.info("Saved device: {}", device.getName());
                return true;
            }

        } catch (SQLException e) {
            logger.error("Failed to save device: {}", device.getName(), e);
        }
        return false;
    }

    public boolean update(Device device) {
        String sql = "UPDATE devices SET name = ?, type = ?, location = ?, device_id = ?, status = ?, update_time = CURRENT_TIMESTAMP WHERE id = ?";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            pstmt.setString(1, device.getName());
            pstmt.setString(2, device.getType());
            pstmt.setString(3, device.getLocation());
            pstmt.setString(4, device.getDeviceId());
            pstmt.setBoolean(5, device.getStatus());
            pstmt.setLong(6, device.getId());

            int affectedRows = pstmt.executeUpdate();
            logger.info("Updated device: {}, affected rows: {}", device.getName(), affectedRows);
            return affectedRows > 0;

        } catch (SQLException e) {
            logger.error("Failed to update device: {}", device.getName(), e);
        }
        return false;
    }

    public boolean delete(Long id) {
        String sql = "DELETE FROM devices WHERE id = ?";

        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            pstmt.setLong(1, id);
            int affectedRows = pstmt.executeUpdate();
            logger.info("Deleted device with id: {}, affected rows: {}", id, affectedRows);
            return affectedRows > 0;

        } catch (SQLException e) {
            logger.error("Failed to delete device with id: {}", id, e);
        }
        return false;
    }

    private Device mapResultSetToDevice(ResultSet rs) throws SQLException {
        Device device = new Device();
        device.setId(rs.getLong("id"));
        device.setName(rs.getString("name"));
        device.setType(rs.getString("type"));
        device.setLocation(rs.getString("location"));
        device.setDeviceId(rs.getString("device_id"));
        device.setStatus(rs.getBoolean("status"));
        device.setCreateTime(rs.getTimestamp("create_time"));
        device.setUpdateTime(rs.getTimestamp("update_time"));
        return device;
    }
}
